﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Transactions;
using SMA.GENTEv1.Dados;

namespace SMA.GENTEv1
{
    public class ContratoNotasEmitidas
    {
        #region Variaveis Membro
        private int _idContratoNFEmitida;
        private string _nrNF;
        private Cidade _localidade;
        private DateTime? _dtEmissao;
        private DateTime? _dtPagamento;
        private string _obs;
        private string _path;
        private Contrato _contrato;
        private GENTEEntities _context;
        private DataTable _dados = new DataTable();
        #endregion

        #region Parametros
        public int IdContratoNFEmitida
        {
            get { return _idContratoNFEmitida; }
            set { _idContratoNFEmitida = value; }
        }

        public string NrNF
        {
            get { return _nrNF; }
            set { _nrNF = value; }
        }
        
        public Cidade Localidade
        {
            get { return _localidade; }
            set { _localidade = value; }
        }
        
        public DateTime? DtEmissao
        {
            get { return _dtEmissao; }
            set { _dtEmissao = value; }
        }
        
        public DateTime? DtPagamento
        {
            get { return _dtPagamento; }
            set { _dtPagamento = value; }
        }
        
        public string Obs
        {
            get { return _obs; }
            set { _obs = value; }
        }
        
        public string Path
        {
            get { return _path; }
            set { _path = value; }
        }

        public Contrato Contrato
        {
            get { return _contrato; }
            set { _contrato = value; }
        }
        #endregion

        #region Construtores
        public ContratoNotasEmitidas()
        {
            _context = new GENTEEntities();
        }

        public ContratoNotasEmitidas(int _idcontrNFemitida, bool carregaContrato, bool carregaLocalidade)
        {
            _context = new GENTEEntities();
            Carregar(_idcontrNFemitida, carregaContrato, carregaLocalidade);
        }
        #endregion

        #region Métodos Privados
        private void Carregar(int _idcontrNFemitida, bool carregaContrato, bool carregaLocalidade)
        {
            try
            {
                var consulta = from nfemitida in _context.tab_contrato_nf_emitidas
                               where nfemitida.id_contrato_nf_emitida == _idcontrNFemitida
                               select new
                               {
                                   nfemitida.id_contrato_nf_emitida,
                                   id_contrato = (nfemitida.tab_contrato.Id_contrato == null) ? 0 : nfemitida.tab_contrato.Id_contrato,
                                   nfemitida.nr_nf,
                                   id_cidade = (nfemitida.tab_cidade.id_cidade == null) ? 0 : nfemitida.tab_cidade.id_cidade,
                                   nfemitida.dt_emissao,
                                   nfemitida.dt_pagamento,
                                   nfemitida.obs,
                                   nfemitida.path,
                               };

                var listConsulta = consulta.ToList();

                foreach (var list in listConsulta)
                {
                    this._idContratoNFEmitida = list.id_contrato_nf_emitida;
                    this._nrNF = list.nr_nf;
                    this._dtEmissao = list.dt_emissao;
                    this._dtPagamento = list.dt_pagamento;
                    this._obs = list.obs;
                    this._path = list.path;

                    if (carregaContrato)
                        this._contrato = new Contrato(list.id_contrato);
                    else
                    {
                        this._contrato = new Contrato();
                        this._contrato.IdContrato = list.id_contrato;
                    }

                    if (carregaLocalidade)
                        this._localidade = new Cidade(list.id_cidade);
                    else
                    {
                        this._localidade = new Cidade();
                        this._localidade.IdCidade = list.id_cidade;
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private int RetornaIdContratoNFEmitida()
        {
            try
            {
                int _idNFemitida = 0;

                var consulta = (from nfemitidas in _context.tab_contrato_nf_emitidas
                                orderby nfemitidas.id_contrato_nf_emitida descending 
                                select new
                                {
                                    nfemitidas.id_contrato_nf_emitida
                                }).Take(1);

                _idNFemitida = consulta.ToList()[0].id_contrato_nf_emitida;

                return _idNFemitida;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private void AtualizarPath(string path)
        {
            try
            {
                tab_contrato_nf_emitidas tabContratoNFEmitidas = (from nfemitidas in _context.tab_contrato_nf_emitidas
                                                                  where nfemitidas.id_contrato_nf_emitida == this._idContratoNFEmitida
                                                                  select nfemitidas).First();

                tabContratoNFEmitidas.path = path;
                _context.SaveChanges();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private bool VerificaCadastro()
        {
            try
            {
                bool _verifica = false;

                if (this._contrato == null)
                    throw new Exception("É necessário informar o contrato!");

                if (this._contrato.IdContrato == 0)
                    throw new Exception("É necessário informar o contrato!");

                if (this._dtPagamento == null)
                    throw new Exception("É necessário informar o mês e ano da nota!");

                if (this._nrNF == string.Empty)
                    throw new Exception("É necessário informar o número da nota!");

                if (this._dtEmissao == null)
                    throw new Exception("É necessário informar a data de emissão da nota!");

                if (this._idContratoNFEmitida == 0)
                {
                    var consulta = (from nfemitidas in _context.tab_contrato_nf_emitidas
                                    where nfemitidas.tab_contrato.Id_contrato == this._contrato.IdContrato
                                    && nfemitidas.nr_nf == this._nrNF
                                    select new
                                    {
                                        nfemitidas.id_contrato_nf_emitida
                                    });

                    if (consulta.ToList().Count > 0)
                        throw new Exception("Foi encontrado o lançamento de uma nota fiscal para o contrato informado. Operação cancelada!");
                }

                _verifica = true;
                return _verifica;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private static Expression<Func<TElement, bool>> BuildContainsExpression<TElement, TValue>(Expression<Func<TElement, TValue>> valueSelector, IEnumerable<TValue> values)
        {
            if (null == valueSelector)
            {
                throw new
                    ArgumentNullException("valueSelector");
            }
            if (null == values) { throw new ArgumentNullException("values"); }

            ParameterExpression p = valueSelector.Parameters.Single();
            if (!values.Any())
            {
                return e => false;
            }

            var equals = values.Select(value =>
            (Expression)Expression.Equal(valueSelector.Body, Expression.Constant(value,
            typeof(TValue))));
            var body = equals.Aggregate<Expression>((accumulate, equal) =>
            Expression.Or(accumulate, equal));
            return Expression.Lambda<Func<TElement, bool>>(body, p);
        }

        private void EstruturaDadosNotasEmitidas()
        {
            DataColumn idNotaEmitida = new DataColumn();
            idNotaEmitida.ColumnName = "IdContratoNFEmitida";
            idNotaEmitida.DataType = Type.GetType("System.Int32");
            _dados.Columns.Add(idNotaEmitida);

            DataColumn descricaoContrato = new DataColumn();
            descricaoContrato.ColumnName = "DescricaoContrato";
            descricaoContrato.DataType = Type.GetType("System.String");
            _dados.Columns.Add(descricaoContrato);

            DataColumn mes = new DataColumn();
            mes.ColumnName = "Mes";
            mes.DataType = Type.GetType("System.String");
            _dados.Columns.Add(mes);

            DataColumn ano = new DataColumn();
            ano.ColumnName = "Ano";
            ano.DataType = Type.GetType("System.Int32");
            _dados.Columns.Add(ano);

            DataColumn numNota = new DataColumn();
            numNota.ColumnName = "NumNota";
            numNota.DataType = Type.GetType("System.String");
            _dados.Columns.Add(numNota);

            DataColumn cidade = new DataColumn();
            cidade.ColumnName = "Localidade";
            cidade.DataType = Type.GetType("System.String");
            _dados.Columns.Add(cidade);

            DataColumn obs = new DataColumn();
            obs.ColumnName = "Obs";
            obs.DataType = Type.GetType("System.String");
            _dados.Columns.Add(obs);

            DataColumn caminho = new DataColumn();
            caminho.ColumnName = "Path";
            caminho.DataType = Type.GetType("System.String");
            _dados.Columns.Add(caminho);
        }
        #endregion

        #region Métodos Publicos
        public List<ContratoNotasEmitidas> SelectPor(int[] _contratos, int[] _anos, int[] _meses, bool carregarContratos, bool carregarLocalidades)
        {
            try
            {
                List<ContratoNotasEmitidas> listNotasEmitidas = new List<ContratoNotasEmitidas>();

                var consulta = (from nfemitidas in (_contratos[0] != 0) ? _context.tab_contrato_nf_emitidas.Where((BuildContainsExpression<tab_contrato_nf_emitidas, int>(item => item.tab_contrato.Id_contrato, _contratos))) : _context.tab_contrato_nf_emitidas
                                join nfemitidasanos in (_anos[0] != 0) ? _context.tab_contrato_nf_emitidas.Where((BuildContainsExpression<tab_contrato_nf_emitidas, int>(item => item.dt_pagamento.Value.Year, _anos))) : _context.tab_contrato_nf_emitidas on nfemitidas.id_contrato_nf_emitida equals nfemitidasanos.id_contrato_nf_emitida
                                join nfemitidasmeses in (_meses[0] != 0) ? _context.tab_contrato_nf_emitidas.Where((BuildContainsExpression<tab_contrato_nf_emitidas, int>(item => item.dt_pagamento.Value.Month, _meses))) : _context.tab_contrato_nf_emitidas on nfemitidasanos.id_contrato_nf_emitida equals nfemitidasmeses.id_contrato_nf_emitida
                                select new
                                {
                                    nfemitidas.id_contrato_nf_emitida,
                                    id_contrato = (nfemitidas.tab_contrato.Id_contrato == null) ? 0 : nfemitidas.tab_contrato.Id_contrato,
                                    nfemitidas.nr_nf,
                                    id_cidade = (nfemitidas.tab_cidade.id_cidade == null) ? 0 : nfemitidas.tab_cidade.id_cidade,
                                    nfemitidas.dt_emissao,
                                    nfemitidas.dt_pagamento,
                                    nfemitidas.obs,
                                    nfemitidas.path
                                });

                var listConsulta = consulta.ToList();

                foreach (var list in listConsulta)
                {
                    ContratoNotasEmitidas nfemitida = new ContratoNotasEmitidas();
                    nfemitida.IdContratoNFEmitida = list.id_contrato_nf_emitida;

                    if (carregarContratos)
                        nfemitida.Contrato = new Contrato(list.id_contrato);
                    else
                    {
                        nfemitida.Contrato = new Contrato();
                        nfemitida.Contrato.IdContrato = list.id_contrato;
                    }

                    nfemitida.NrNF = list.nr_nf;

                    if (carregarLocalidades)
                        nfemitida.Localidade = new Cidade(list.id_cidade);
                    else
                    {
                        nfemitida.Localidade = new Cidade();
                        nfemitida.Localidade.IdCidade = list.id_cidade;
                    }

                    nfemitida.DtEmissao = list.dt_emissao;
                    nfemitida.DtPagamento = list.dt_pagamento;
                    nfemitida.Obs = list.obs;
                    nfemitida.Path = list.path;

                    listNotasEmitidas.Add(nfemitida);
                }

                return listNotasEmitidas;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public DataTable ExibirDadosNotasEmitidas(int[] _contratos, int[] _anos, int[] _meses)
        {
            try
            {
                List<ContratoNotasEmitidas> listNotasEmitidas = SelectPor(_contratos, _anos, _meses, true, true);

                EstruturaDadosNotasEmitidas();

                DataRow linha;
                foreach (ContratoNotasEmitidas item in listNotasEmitidas)
                {
                    linha = _dados.NewRow();
                    linha["IdContratoNFEmitida"] = item.IdContratoNFEmitida;
                    linha["DescricaoContrato"] = item.Contrato.Descricao;

                    string mes = "";
                    if (item.DtPagamento != null)
                    {
                        mes = System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(item.DtPagamento.Value.Month);
                        mes = Char.ToUpper(mes[0]) + mes.Substring(1);
                    }
                    linha["Mes"] = mes;
                    linha["Ano"] = (item.DtPagamento != null) ? item.DtPagamento.Value.Year : 0;
                    
                    linha["NumNota"] = item.NrNF;
                    linha["Localidade"] = item.Localidade.NomeCidade;
                    linha["Obs"] = item.Obs;
                    linha["Path"] = item.Path;
                    _dados.Rows.Add(linha);
                }

                return _dados;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public List<Cidade> CarregarLocalidadesNota(int _organizacao)
        {
            try
            {
                List<Cidade> listCidade = new List<Cidade>();

                var consulta = from organizacao in _context.tab_organizacao
                               join organizacaomatriz in _context.tab_organizacao_relacao_matriz on organizacao.Id_organizacao equals organizacaomatriz.tab_organizacao.Id_organizacao
                               where organizacao.Id_organizacao == _organizacao
                               select new
                               {
                                   organizacao.Id_organizacao
                               };

                if (consulta.ToList().Count == 0)
                {
                    var consultaCidades = from organizacao in _context.tab_organizacao
                                          join organizacaoend in _context.tab_organizacao_endereco on organizacao.Id_organizacao equals organizacaoend.tab_organizacao.Id_organizacao
                                          join cidade in _context.tab_cidade on organizacaoend.tab_cidade.id_cidade equals cidade.id_cidade
                                          where organizacao.Id_organizacao == _organizacao
                                          select new
                                          {
                                              cidade.id_cidade,
                                              cidade.cidade
                                          };

                    var listConsulta = consultaCidades.ToList();

                    foreach (var list in listConsulta)
                    {
                        Cidade cidade = new Cidade();
                        cidade.IdCidade = list.id_cidade;
                        cidade.NomeCidade = list.cidade;
                        
                        listCidade.Add(cidade);
                    }
                }
                else
                {
                    var consultaCidades = from organizacao in _context.tab_organizacao
                                          join organrelacao in _context.tab_organizacao_relacao_matriz on organizacao.Id_organizacao equals organrelacao.tab_organizacao1.Id_organizacao
                                          join organizacaoend in _context.tab_organizacao_endereco on organizacao.Id_organizacao equals organizacaoend.tab_organizacao.Id_organizacao
                                          join cidade in _context.tab_cidade on organizacaoend.tab_cidade.id_cidade equals cidade.id_cidade
                                          where organrelacao.tab_organizacao.Id_organizacao == _organizacao
                                          select new
                                          {
                                              cidade.id_cidade,
                                              cidade.cidade
                                          };

                    var listConsulta = consultaCidades.ToList();

                    foreach (var list in listConsulta)
                    {
                        Cidade cidade = new Cidade();
                        cidade.IdCidade = list.id_cidade;
                        cidade.NomeCidade = list.cidade;

                        listCidade.Add(cidade);
                    }
                }

                return listCidade;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public void Salvar()
        {
            try
            {
                if (VerificaCadastro())
                {
                    if (this._idContratoNFEmitida == 0)
                    {
                        tab_contrato_nf_emitidas tabContratoNFEmitidas = new tab_contrato_nf_emitidas();

                        if (this._contrato != null)
                            tabContratoNFEmitidas.tab_contratoReference.EntityKey = new System.Data.EntityKey("GENTEEntities.tab_contrato", "Id_contrato", this._contrato.IdContrato);
                        else
                            tabContratoNFEmitidas.tab_contratoReference.EntityKey = null;
                        tabContratoNFEmitidas.nr_nf = this._nrNF;
                        if (this._localidade != null)
                            tabContratoNFEmitidas.tab_cidadeReference.EntityKey = new System.Data.EntityKey("GENTEEntities.tab_cidade", "id_cidade", this._localidade.IdCidade);
                        else
                            tabContratoNFEmitidas.tab_cidadeReference.EntityKey = null;
                        tabContratoNFEmitidas.dt_emissao = this._dtEmissao;
                        tabContratoNFEmitidas.dt_pagamento = this._dtPagamento;
                        tabContratoNFEmitidas.obs = this._obs;

                        _context.AddTotab_contrato_nf_emitidas(tabContratoNFEmitidas);
                        _context.SaveChanges();

                        if (this._path != string.Empty)
                        {
                            this._idContratoNFEmitida = RetornaIdContratoNFEmitida();

                            string _nomearquivo = "";
                            TipoDocumento tipodocto = new TipoDocumento();
                            _nomearquivo = tipodocto.ObterNomeDocumento(this._contrato.OrganizacaoRelacao.OrganizacaoPrestador.IdOrganizacao, TipoDocumento.TipoDocto.Notas_Fiscais_Emitidas, this._idContratoNFEmitida.ToString());

                            AtualizarPath(this._path + _nomearquivo);
                            this._path = this._path + _nomearquivo;
                        }
                    }
                    else
                    {
                        tab_contrato_nf_emitidas tabContratoNFEmitidas = (from nfemitidas in _context.tab_contrato_nf_emitidas
                                                                          where nfemitidas.id_contrato_nf_emitida == this._idContratoNFEmitida
                                                                          select nfemitidas).First();

                        if (this._contrato != null)
                            tabContratoNFEmitidas.tab_contratoReference.EntityKey = new System.Data.EntityKey("GENTEEntities.tab_contrato", "Id_contrato", this._contrato.IdContrato);
                        else
                            tabContratoNFEmitidas.tab_contratoReference.EntityKey = null;
                        tabContratoNFEmitidas.nr_nf = this._nrNF;
                        if (this._localidade != null)
                            tabContratoNFEmitidas.tab_cidadeReference.EntityKey = new System.Data.EntityKey("GENTEEntities.tab_cidade", "id_cidade", this._localidade.IdCidade);
                        else
                            tabContratoNFEmitidas.tab_cidadeReference.EntityKey = null;
                        tabContratoNFEmitidas.dt_emissao = this._dtEmissao;
                        tabContratoNFEmitidas.dt_pagamento = this._dtPagamento;
                        tabContratoNFEmitidas.obs = this._obs;

                        if (this._path != string.Empty)
                        {
                            string _nomearquivo = "";
                            TipoDocumento tipodocto = new TipoDocumento();
                            _nomearquivo = tipodocto.ObterNomeDocumento(this._contrato.OrganizacaoRelacao.OrganizacaoPrestador.IdOrganizacao, TipoDocumento.TipoDocto.Notas_Fiscais_Emitidas, this._idContratoNFEmitida.ToString());

                            tabContratoNFEmitidas.path = this._path + _nomearquivo;
                            this._path = this._path + _nomearquivo;
                        }

                        _context.SaveChanges();
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public void Excluir()
        {
            //using (TransactionScope scope = new TransactionScope())
            //{
                try
                {
                    var consulta = from nfemitidas in _context.tab_contrato_nf_emitidas
                                   where nfemitidas.id_contrato_nf_emitida == this._idContratoNFEmitida 
                                   select nfemitidas;

                    var listConsulta = consulta.ToList();

                    string _caminhodoc = "";
                    foreach (var list in listConsulta)
                    {
                        _caminhodoc = list.path;
                        _context.DeleteObject(list);
                        _context.SaveChanges();

                        if ((_caminhodoc != "") && (System.IO.File.Exists(_caminhodoc)))
                            System.IO.File.Delete(_caminhodoc);
                    }

                    //scope.Complete();
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            //}
        }
        #endregion
    }
}
